package com.example.demo.common;

import com.alibaba.fastjson.JSONObject;
import com.example.demo.common.constant.ResultCode;
import com.example.demo.exception.BusinessException;
import com.github.f4b6a3.ulid.UlidCreator;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.Version;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Decoder;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;

@Slf4j
public class Func {
    //base64 编码
    public static String encode(String resoure) {
        if (Valid.isEmpty(resoure)) {
            return "";
        }
        return Base64.getEncoder().encodeToString(resoure.getBytes());
    }

    //base64 解码
    public static String decode(String coder) {
        if (Valid.isEmpty(coder) || !Valid.isBase64(coder)) {
            return "";
        }
        return new String(Base64.getDecoder().decode(coder));
    }

    //获取系统根路径（尾部没有“/”）
    public static String getRootPath() {
        return System.getProperty("user.dir");
    }

    //获取6位随机数
    public static String get6Random() {
        int intFlag = (int) (Math.random() * 1000000);
        String flag = String.valueOf(intFlag);
        if (flag.length() != 6 || flag.charAt(0) != '9') {
            intFlag = intFlag + 100000;
        }
        return String.valueOf(intFlag);
    }

    //获取当前年份
    public static int getYear() {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        String today = df.format(new Date());
        int year = 0;
        if (today.length() >= 4) {
            year = Integer.parseInt(today.substring(0, 4));
        }
        return year;
    }

    //获取当前月份
    public static int getMonth() {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        String today = df.format(new Date());
        int month = 0;
        if (today.length() >= 8) {
            month = Integer.parseInt(today.split("-")[1]);
        }
        return month;
    }

    //获取 yyyy-MM-dd 格式的时间
    public static String getToday() {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        return df.format(new Date());
    }

    //获取 yyyy-MM-dd HH:mm:ss 格式的时间
    public static LocalDateTime getNow() {
        return LocalDateTime.now();
    }

    //获取正确的格式化日期
    public static String getSimpleFormatDate(String oldDate) {
        SimpleDateFormat sdfOldDate = new SimpleDateFormat("yy-MM-dd");
        SimpleDateFormat sdfNewDate = new SimpleDateFormat("yyyy-MM-dd");
        try {
            return sdfNewDate.format(sdfOldDate.parse(oldDate));
        } catch (ParseException e) {
            return "";
        }
    }

    //获取访问者的IP地址
    public static String getIP(HttpServletRequest request) {
        String ipAddress = null;
        ipAddress = request.getHeader("x-forwarded-for");
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
            if (ipAddress.equals("127.0.0.1")) {
                //根据网卡取本机配置的IP
                InetAddress inet = null;
                try {
                    inet = InetAddress.getLocalHost();
                } catch (UnknownHostException ex) {
                    ex.printStackTrace();
                }
                ipAddress = inet.getHostAddress();
            }
        }

        //对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
        if (ipAddress != null && ipAddress.length() > 15) {
            if (ipAddress.indexOf(",") > 0) {
                ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
            }
        }

        return ipAddress;
    }

    //获取上传的文件
    public static File getUploadFile(MultipartFile multipartFile) {
        File file;
        try {
            String originalFilename = multipartFile.getOriginalFilename();
            String prefix = originalFilename.substring(originalFilename.lastIndexOf("."));
            file = File.createTempFile(originalFilename, prefix);
            multipartFile.transferTo(file);
            file.deleteOnExit();
        } catch (IOException e) {
            return null;
        }
        return file;
    }

    //获取Excel数据
    public static List<JSONObject> getExcelData(MultipartFile multipartFile, String[] fieldList, int firstRow) {
        List<JSONObject> list = new ArrayList<>();
        try {
            String fileExname = multipartFile.getOriginalFilename().substring(multipartFile.getOriginalFilename().lastIndexOf(".") + 1).toLowerCase();
            InputStream is = new FileInputStream(Func.getUploadFile(multipartFile));
            Workbook rwb = fileExname.equals("xls") ? new HSSFWorkbook(is) : new XSSFWorkbook(is);
            Sheet sheet = rwb.getSheetAt(0);
            int rows = sheet.getPhysicalNumberOfRows();

            for (int i = firstRow; i < rows; i++) {
                Row row = sheet.getRow(i);
                int cols = row.getLastCellNum();
                for (int j = 0; j < cols; j++) {
                    JSONObject info = new JSONObject();
                    for (String field : fieldList) {
                        info.put(field, row.getCell(j++).toString().trim());
                    }
                    list.add(info);
                }
            }
        }
        catch (IOException ignored) { }

        return list;
    }

    // 根据模板生成Word文件
    public static void createWordWithTemplate(List<JSONObject> excelData, String[][] fileNameRole, String templatePath, String templateName, String filePath, boolean isClear) {
        // 是否清除遗留文件
        if (isClear) {
            File doc = new File(filePath);
            File[] docList = doc.listFiles();
            for (File f : docList) {
                f.delete();
            }
        }

        Writer out = null;
        try {
            for (JSONObject info : excelData) {
                // 根据文件名规则自动生成文件名
                String fileName = "";
                for (String[] name : fileNameRole) {
                    fileName += info.getString(name[0]) + name[1];
                }
                fileName += ".doc";
                String fileUrl = filePath + fileName;

                // 若不要求清除遗留文件，且文件已经存在，则跳过
                if (!isClear) {
                    File doc = new File(fileUrl);
                    if (doc.exists() && doc.isFile()) {
                        continue;
                    }
                }

                // 生成Word文件
                Configuration configuration = new Configuration(new Version("2.3.28"));
                configuration.setDefaultEncoding("UTF-8");
                configuration.setDirectoryForTemplateLoading(new File(templatePath));
                Template tem = configuration.getTemplate(templateName, "UTF-8");
                out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileUrl), StandardCharsets.UTF_8));
                tem.process(info, out);
                out.flush();
            }
        }
        catch (IOException | TemplateException ignored) {
            log.error(ResultCode.TEMPLATE_CONVERT_WORD_ERROR.getMessage());
            throw new BusinessException(ResultCode.TEMPLATE_CONVERT_WORD_ERROR);
        }
        finally {
            if (out != null) {
                try {
                    out.close();
                }
                catch (Exception ignored2) { }
            }
        }
    }

    //获取Base64字符串的文件名
    public static String getFileName(String fileBase64) {
        if (Valid.isEmpty(fileBase64)) {
            return "";
        }
        if (!fileBase64.contains(";base64,")) {
            return fileBase64;
        }

        String fileExName = fileBase64.split(";base64,")[0].replace("data:", "");
        String fileName = getUUID();
        switch (fileExName) {
            case "image/jpeg":
                fileName += ".jpg";
                break;
            case "image/jpg":
                fileName += ".jpg";
                break;
            case "image/png":
                fileName += ".png";
                break;
            case "application/vnd.ms-excel":
                fileName += ".xls";
                break;
            case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
                fileName += ".xlsx";
                break;
            case "application/msword":
                fileName += ".doc";
                break;
            default:
                fileName += ".jpg";
        }

        return fileName;
    }

    //将Base64字符串保存为图片（之所以与保存文件区别，是由于保存图片还需要压缩）
    public static void savePic(String fileBase64, String filePath) {
        String base64 = fileBase64.split(";base64,")[1];
        byte[] bytes = null;
        InputStream stream = null;
        try {
            bytes = new BASE64Decoder().decodeBuffer(base64);
            stream = new ByteArrayInputStream(bytes);
            Thumbnails.of(stream).scale(1.0f).toFile(filePath);
        }
        catch (Exception ex) {
            log.error(ResultCode.BASE64_CONVERT_PIC_ERROR.getMessage());
            throw new BusinessException(ResultCode.BASE64_CONVERT_PIC_ERROR);
        }
        finally {
            if (stream != null) {
                try {
                    stream.close();
                }
                catch (Exception ignored) { }
            }
            if (bytes != null) {
                bytes.clone();
            }
        }
    }

    //将Base64字符串保存为文件
    public static void saveFile(String fileBase64, String filePath) {
        if (fileBase64.contains("data:")) {
            int start = fileBase64.indexOf(",");
            fileBase64 = fileBase64.substring(start + 1);
        }
        fileBase64 = fileBase64.replaceAll("\r|\n", "");
        fileBase64 = fileBase64.trim();

        byte[] bytes = null;
        FileOutputStream fos = null;
        try {
            File file = new File(filePath);
            bytes = Base64.getDecoder().decode(fileBase64);
            fos = new FileOutputStream(file);
            fos.write(bytes);
            fos.flush();
        }
        catch (Exception ex) {
            log.error(ResultCode.BASE64_CONVERT_FILE_ERROR.getMessage());
            throw new BusinessException(ResultCode.BASE64_CONVERT_FILE_ERROR);
        }
        finally {
            if (fos != null) {
                try {
                    fos.close();
                }
                catch (Exception ignored) { }
            }
            if (bytes != null) {
                bytes.clone();
            }
        }
    }

    //删除文件
    public static void deleteFile(String filePath) {
        File file = new File(filePath);
        if (file.exists() && file.isFile()) {
            file.delete();
        }
    }

    //获取唯一的UUID
    public static String getUUID() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    //获取唯一的ULID（getMonotonicUlid有顺序）
    public static String getULID() {
        return UlidCreator.getMonotonicUlid().toString();
        // return UlidCreator.getMonotonicUlid(1670837655000L).toString();
        // return UlidCreator.getUlid().toString();
    }

    //获取雪花ID
    public static String getSnowID() {
        return String.valueOf(new SnowflakeId(1).generateId());
    }

    //获取雪花ID（可传入服务器节点ID）
    public static String getSnowID(long nodeId) {
        return String.valueOf(new SnowflakeId(nodeId).generateId());
    }

    public static HttpServletRequest getHttpRequest() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            return null;
        }
        return attributes.getRequest();
    }

    public static HttpServletResponse getHttpResponse() {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            return null;
        }
        return attributes.getResponse();
    }

    public static void print(Object content) {
        System.out.println(content);
    }
}
